package com.moyuwanjia_anno.utils;
import com.moyuwanjia_anno.utils.ConnectionUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.sql.SQLException;

/**
 * @author 摸鱼丸加~
 * @create 2022-07-08 17:39
 * 切面类，将其中的事务看做通知方法,也就是将当前类看做通知类
 */
@Slf4j
@Aspect
@Component(value = "TransactionManager")
public class TransactionManager {
    @Autowired
    private ConnectionUtils connectionUtils;
    //切入点表达式
    @Pointcut("execution(* com.moyuwanjia_anno.service.Impl.*.*(..))")
    public void pt1(){}

    /**
     * 开启事务，关闭自动提交
     */
//    @Before("pt1()")
    public void beginTransaction(){
        try {
            log.info("前置通知");
            connectionUtils.getThreadConnection().setAutoCommit(false);
        } catch (SQLException sqlException) {
            sqlException.printStackTrace();
        }
    }

    /**
     * 提交事务
     */
//    @AfterReturning("pt1()")
    public void commit(){
        try {
            log.info("后置通知");
            connectionUtils.getThreadConnection().commit();
        } catch (SQLException sqlException) {
            sqlException.printStackTrace();
        }
    }

    /**
     * 事务回滚
     */
//    @AfterThrowing("pt1()")
    public void rollback(){
        try {
            log.info("异常通知");
            connectionUtils.getThreadConnection().rollback();
        } catch (SQLException sqlException) {
            sqlException.printStackTrace();
        }
    }

    /**
     * 释放连接
     */
//    @After("pt1()")
    public void release(){
         try {
             log.info("最终通知");
            connectionUtils.getThreadConnection().close();
            connectionUtils.removeConnection();//将线程和连接解绑
        } catch (SQLException sqlException) {
            sqlException.printStackTrace();
        }
    }

    /**
     * 不需要逐一标注通知方法，直接使用环绕通知
     */
    @Around("pt1()")
    public Object around(ProceedingJoinPoint point){
        System.out.println("环绕通知");
        Object _returnValue = null;
        this.beginTransaction();
        try {
            Object[] args =  point.getArgs();//获取方法所执行的参数
            _returnValue = point.proceed(args);//明确调用业务层方法
            this.commit();
            return _returnValue;
        } catch (Throwable throwable) {
            this.rollback();
            throwable.printStackTrace();
        } finally {
            this.release();
        }
        return _returnValue;
    }
}
